#include "ui_popup.h"
#include "game_flow_manager.h"

#include "script/scripthelper.h"

#include "ui/ui_widget.h"
#include "ui/ui_manager.h"

#include "util/timer.h"				// log
#include "util/log.h"				// log
#include "util/common_macros.h"		// macros
#include "util/mmgr.h"		    
#include "util/profiler.h"		    
#include <stdlib.h>
using namespace gameflow;


UIPopup::UIPopup(const std::string& Panel, const std::string& EndButton) :
	m_Name(Panel),
	m_Panel(Panel),
	m_pPanel(NULL),
	m_BGAlpha(0.7f),
	m_PreventClickthroughs(true),
	m_CurrentIdx(0)
{
	m_pPanel = ui::UIManager::Instance().AddPanel(m_Panel);
	if (m_pPanel)
	{
		m_Name = m_pPanel->GetName();

		if (!EndButton.empty())
		{
			SetWidgetFunctor(EndButton, UI_DELEGATE(UIPopup, OnClosePanel));
		}
	}
	ForceHide();
}

UIPopup::~UIPopup()
{
	//ForceHide();
}

void DELEGATE_CALL	UIPopup::OnClosePanel(ui::UIWidget::WIDGET_EVENT Event, ui::UIWidget* pWidget)
{
	Hide(NULL);
}

void	UIPopup::Show(ui::UIMover::MoverEvent Event)
{
	if (!m_pPanel) return;
	// make sure it's shown
	m_pPanel->SetIsVisible(true);
	m_pPanel->SetBlockAllEvents(m_PreventClickthroughs);
	ui::UIManager::Instance().PushPanelToFront(m_pPanel);
	// attach a show action set

	UIPopupAnimations&	Animations = UIPopupAnimations::Instance();
	Animations.ApplyAnimation(m_pPanel, Animations.GetStartAnim(), 0, false);
	
}

void	UIPopup::Hide(ui::UIMover::MoverEvent Event)
{
	if (!m_pPanel) return;
	// make sure it's shown
	m_pPanel->SetIsVisible(false);
	// attach a hide-action set

	UIPopupAnimations&	Animations = UIPopupAnimations::Instance();
	Animations.ApplyAnimation(m_pPanel, Animations.GetEndAnim(), 0, true);
}
void	UIPopup::Render()
{
	// nothing
}
void	UIPopup::Tick(float dt)
{
	// nothing
}
void	UIPopup::Init()
{
	// all popups start hidden
	ForceHide();
}
void	UIPopup::ForceHide()
{
	if (m_pPanel)
	{
		m_pPanel->SetIsVisible(false);
	}
}
void	UIPopup::OnShowComplete()
{

}

void	UIPopup::OnHideComplete()
{
	ForceHide();	// force it to no longer draw
}


ui::UIWidget*	UIPopup::GetWidget(const std::string& Name)
{
	if (!m_pPanel) return NULL;
	return m_pPanel->GetWidgetByName(Name);
}
void	UIPopup::SetWidgetText(const std::string& Name, const std::string& Text)
{
	ui::UIWidget*	pWidget = GetWidget(Name);
	if (!pWidget)	return;
	pWidget->SetTextA(Text);
}

void			UIPopup::SetWidgetFunctor(const std::string& Widget, ui::UIWidget::tdgEvent Event, ui::UIWidget::WIDGET_EVENT EventID)
{
	ui::UIWidget*	pWidget = GetWidget(Widget);
	if (!pWidget)	return;
	// check if one already exists?
	pWidget->SetEventDg(EventID, Event);
}

void	UIPopup::SetWidgetPopup(const std::string& WidgetName, const std::string& PopupName, 
								GameTransition::TransitionEvent		OnStart, 
								ui::UIMover::MoverEvent	OnFinish)

{
	ui::UIWidget*	pWidget = GetWidget(WidgetName);
	UIPopupManager::Instance().SetWidgetPopup(pWidget, PopupName, OnStart, OnFinish);
}

void	UIPopup::SetupTransition(const std::string& Widget, 
								const std::string& ToState, 
								const std::string& Sound, 
								GameTransition::TransitionEvent	OnFinish)
{
	ui::UIWidget*	pWidget = GetWidget(Widget);
	if (!pWidget)
	{
		_LOG(MSG_ERROR, "No ui Widget " << Widget << " exists in the pupup " << GetName());
		return;
	}
	GameFlowManager::Instance().GetTransition().SetupTransitionDg(
		pWidget, ToState, Sound, TRANSITION_DELEGATE(UIPopup, OnTransition), OnFinish);
}

void DELEGATE_CALL	UIPopup::OnTransition(GameTransition* pTransition)
{
	Hide(NULL);
}

void				UIPopup::DPadNav(int	DirX, int DirY, int	Triggered)
{
	if (m_NavList.empty()) return;
	ui::UIWidget*	pOld = m_NavList[m_CurrentIdx];
	m_CurrentIdx+=DirY;
	if (m_CurrentIdx < 0) m_CurrentIdx = (int)m_NavList.size()-1;
	if (m_CurrentIdx >= (int)m_NavList.size()) m_CurrentIdx = 0;

	ui::UIWidget*	pElement = m_NavList[m_CurrentIdx];
	if (!pElement) return;
	pOld->SetState(ui::UIWidget::WS_MOUSE_OFF);
	pElement->SetState(ui::UIWidget::WS_MOUSE_OVER);

	if (Triggered == 1)	// activate current
	{
		pElement->TriggerEvent(ui::UIWidget::WE_LMB_RELEASE);
	}
	if (DirX == -1)	// activate current
	{
		pElement->TriggerEvent(ui::UIWidget::WE_LEFT_KEY);
	}
	if (DirX ==  1)	// activate current
	{
		pElement->TriggerEvent(ui::UIWidget::WE_RIGHT_KEY);
	}}


//////////////////////////////////////////////////////////
/// system to apply animations to this
UIPopupAnimations&	UIPopupAnimations::Instance()
{
	static	UIPopupAnimations	Inst;
	return Inst;
}

UIPopupAnimations::UIPopupAnimations()
{
	Load("infos/popup_anim.lua");

	if (!GetState()) return;	// load failed

	LuaPlus::LuaObject	Start = GetTable("StartAnimations");
	if (Start.IsTable()) 
	{	
		for (int i=0; i<Start.GetTableCount(); i++)
		{
			LuaPlus::LuaObject TempObj = Start[i+1];
			m_StartAnimations.push_back(script::ScriptHelper::GetString(TempObj));
		}
	}
	LuaPlus::LuaObject	End = GetTable("EndAnimations");
	if (End.IsTable()) 
	{	
		for (int i=0; i<End.GetTableCount(); i++)
		{
			LuaPlus::LuaObject TempObj = End[i+1];
			m_EndAnimations.push_back(script::ScriptHelper::GetString( TempObj ));
		}
	}
}

void	UIPopupAnimations::ApplyAnimation(ui::UIWidget*	pWidget, const std::string& Name, float Delay, bool HideAfter, ui::UIMover::MoverEvent	Event)
{
	using namespace script;
	if (!pWidget) return;
	if (!GetState()) return;

	LuaPlus::LuaObject	Table = GetTable(Name);
	if (!Table.IsTable()) return;

	// okay, quick code for running through an animation set and triggering effects as we go

	pWidget->ClearMovers();		
	math::Vec2	LastPos = pWidget->GetPosition();
	int			Count = (int)Table.GetTableCount();
	float		Time = Delay;
	for (int i=0; i<Count; i++)
	{
		LuaPlus::LuaObject		Obj = Table.GetByIndex(i+1);
		float		Duration = ScriptHelper::GetTableFloat(Obj, "Duration", 1.0f);
		// ignore script
		std::string	Audio	= ScriptHelper::GetTableString(Obj, "Audio", "");
		math::Vec2	Pos		= ScriptHelper::GetTableVec2(Obj, "Pos", LastPos);
		math::Vec2	From	= ScriptHelper::GetTableVec2(Obj, "From", Pos);
		math::Vec2	To		= ScriptHelper::GetTableVec2(Obj, "To", From);
		LastPos = To;
		if (i==0)
		{
			pWidget->SetPosition(From);
		}

		std::string	Anim	= ScriptHelper::GetTableString(Obj, "Anim", "");
		if (!Anim.empty())
			pWidget->AddSetImageMover(Time, Anim);

		math::Vec2	XFade		= ScriptHelper::GetTableVec2(Obj, "XFade", math::Vec2(-2, -2));
		if (XFade.x > -1)	// nasty way to check
		{
			pWidget->AddUIXFadeMover(Time, Duration, XFade);
		}
		ui::UIMover*	pEnd = pWidget->AddUIMoveMover(Time, Duration, From, To);
		if (pEnd)
		{
			if (Event)	pEnd->SetMoverEvent(Event);
			
		}
	}
	if (HideAfter) 
	{
		pWidget->AddUIHideMover();
	}
}


std::string			UIPopupAnimations::GetEndAnim()
{
	if (m_EndAnimations.empty()) return "PopupEnd";
	return m_EndAnimations[rand()% m_EndAnimations.size()];
}

std::string			UIPopupAnimations::GetStartAnim()
{
	if (m_StartAnimations.empty()) return "PopupStart1";
	return m_StartAnimations[rand()% m_StartAnimations.size()];

}


/////////////////////////////////////////////////////

UIPopupManager&		UIPopupManager::Instance()
{
	static UIPopupManager	Inst;
	return Inst;
}
UIPopupManager::UIPopupManager()
{

}

UIPopupManager::~UIPopupManager()
{
	// delete all popups?
	for (unsigned int i=0; i<m_Popups.size(); i++)
		delete m_Popups[i];
	for (unsigned int i=0; i<m_PopupNotification.size(); i++)
		delete m_PopupNotification[i];
}

UIPopup*	UIPopupManager::AddPopup(const std::string& File, const std::string& CloseButton)
{
	UIPopup*	pPopup = GetPopup(File);
	if (pPopup)
	{
		_LOG(MSG_WARNING, "unable to double-add popup " << File);
		return pPopup;
	}
	pPopup = new UIPopup(File, CloseButton);
	m_Popups.push_back(pPopup);
	return pPopup;
}

UIPopup*	UIPopupManager::AddPopup(UIPopup* pPopup)
{
	for (unsigned int i=0; i<m_Popups.size(); i++)
	{
		gameflow::UIPopup* pAldPopup = m_Popups[i];
		if(pPopup == pAldPopup )
			return pPopup;
	}
	m_Popups.push_back(pPopup);
	return pPopup;
}

UIPopup*	UIPopupManager::StartPopup(const std::string& Name, ui::UIMover::MoverEvent Event)
{
	UIPopup* pPopup = GetPopup(Name);
	if (pPopup)
	{
		pPopup->Show(Event);
	}
	return pPopup;
}
void		UIPopupManager::EndPopup(const std::string& Name, ui::UIMover::MoverEvent Event)
{
	UIPopup* pPopup = GetPopup(Name);
	if (pPopup)
	{
		pPopup->Hide(Event);
	}
	return;
}

void		UIPopupManager::HideAllPopups()
{
	for (unsigned int i=0; i<m_Popups.size(); i++)
		m_Popups[i]->ForceHide();
}

void		UIPopupManager::DPadNav(int	DirX, int DirY, int	Triggered)
{
	for (unsigned int i=0; i<m_Popups.size(); i++)
	{
		if (m_Popups[i]->IsActive())
		{
			m_Popups[i]->DPadNav(DirX, DirY, Triggered);
		}
	}
}

UIPopup*	UIPopupManager::GetPopup(const std::string& Name)
{
	for (unsigned int i=0; i<m_Popups.size(); i++)
	{
		if (strcmpi(m_Popups[i]->GetName().c_str(), Name.c_str())==0 || 
			strcmpi(m_Popups[i]->GetPanelName().c_str(), Name.c_str())==0)
			return m_Popups[i];
	}
	return NULL;
}
void		UIPopupManager::SetWidgetPopup(ui::UIWidget* pWidget, const std::string& PopupName, GameTransition::TransitionEvent		OnStart, ui::UIMover::MoverEvent		OnFinish)
{
	if (!pWidget)	return;

	for (unsigned int i=0; i<m_PopupNotification.size(); i++)
	{
		if (m_PopupNotification[i]->pSourceWidget == pWidget)
		{
			// already exists!
			_LOG(MSG_ERROR, "There's already a popup registered for " << pWidget->GetName());
			// provide overriding here instead?
			return;
		}
	}
	UIPopupNotification*	pNewPopup = new UIPopupNotification;
	pNewPopup->OnStart = OnStart;
	pNewPopup->OnFinish = OnFinish;
	pNewPopup->PopupName = PopupName;
	pNewPopup->pSourceWidget = pWidget;
	m_PopupNotification.push_back(pNewPopup);
	pWidget->SetReleaseLMBEventDg(UI_DELEGATE(UIPopupManager, OnPopupClicked));
}

 bool	UIPopupManager::StartYesNo(const std::string& Text, ui::UIWidget::tdgEvent OnYes, ui::UIWidget::tdgEvent OnNo)
 {
	UIPopup*	pPopup = GetPopup("Yesno");
	if (!pPopup || !pPopup->GetPanel())
	{
		pPopup = AddPopup("ui/yesno.ui");		// CHIT: Try re-adding (for our some old games that didn't use SetupUI())
		if (!pPopup || !pPopup->GetPanel())		// really no?
		{
			_LOG(MSG_ERROR, "No valid yes/no box created!");
			return false;
		}
	}
	m_YesNoResponse.pNo = pPopup->GetWidget("NoWidget");
	m_YesNoResponse.pYes = pPopup->GetWidget("YesWidget");
	ui::UIWidget*	pText = pPopup->GetWidget("YesNoText");
	if (!m_YesNoResponse.pNo || !m_YesNoResponse.pYes ||! pText)
	{
		_LOG(MSG_ERROR, "The Yes/No box is missing required widgets!");
		return false;
	}
	
	m_YesNoResponse.pNo->SetTextA("NO");
	m_YesNoResponse.pYes->SetTextA("YES");

	m_YesNoResponse.pNo->SetReleaseLMBEventDg(UI_DELEGATE(UIPopupManager, OnYesNo));
	m_YesNoResponse.pYes->SetReleaseLMBEventDg(UI_DELEGATE(UIPopupManager, OnYesNo));
	
	m_YesNoResponse.OnNo = OnNo;
	m_YesNoResponse.OnYes = OnYes;
	pText->SetTextA(Text);
	StartPopup("YesNo");
	return true;
 }
	
 bool	UIPopupManager::StartPrompt(const std::string& Heading,const std::string& Text, const std::string& OKText, ui::UIWidget::tdgEvent OnOK)
 {
	UIPopup*	pPopup = GetPopup("Prompt");
	if (!pPopup || !pPopup->GetPanel())
	{
		_LOG(MSG_ERROR, "No valid yes/no box created!");
		return false;
	}

	pPopup->SetWidgetText("namebox", Heading);
	pPopup->SetWidgetText("messagebox", Text);
	pPopup->SetWidgetText("btn_ok", OKText);
	pPopup->SetWidgetFunctor("btn_ok", UI_DELEGATE(UIPopupManager, OnPromptOK));
	StartPopup("Prompt");
	m_PromptAction = OnOK;	// this is the actual Payload function... OnPromptOK will just hide the UI
	return true;
 }


void DELEGATE_CALL	UIPopupManager::OnPopupClicked(ui::UIWidget::WIDGET_EVENT Event, ui::UIWidget* pWidget)
{
	for (unsigned int i=0; i<m_PopupNotification.size(); i++)
	{
		if (m_PopupNotification[i]->pSourceWidget == pWidget)
		{
			// if there's an active function tied to OnStart, run it
			if (m_PopupNotification[i]->OnStart)
			{
				m_PopupNotification[i]->OnStart(NULL);	// no transition associated
			}
			// play sound?

			// spawn a transition
			// do we want a specific name?
			StartPopup(m_PopupNotification[i]->PopupName, m_PopupNotification[i]->OnFinish);
			return;
		}
	}
}

void DELEGATE_CALL	UIPopupManager::OnYesNo(ui::UIWidget::WIDGET_EVENT Event, ui::UIWidget* pWidget)
{
	if (pWidget == m_YesNoResponse.pYes && m_YesNoResponse.OnYes)
	{
		m_YesNoResponse.OnYes(Event, pWidget);
	} else
	if (pWidget == m_YesNoResponse.pNo && m_YesNoResponse.OnNo)
	{
		m_YesNoResponse.OnNo(Event, pWidget);
	} 
	EndPopup("YesNo");
}
void DELEGATE_CALL	UIPopupManager::OnPromptOK(ui::UIWidget::WIDGET_EVENT Event, ui::UIWidget* pWidget)
{
	if (m_PromptAction)
	{
		m_PromptAction(Event, pWidget);
	} 
	EndPopup("Prompt");
}

UIPopup*	UIPopupManager::GetActivePopup()
{
	for (unsigned int i=0; i<m_Popups.size(); i++)
	{
		gameflow::UIPopup* pPopup = m_Popups[i];
		if(pPopup->IsActive())
			return pPopup;
	}
	return NULL;
}
